package net.lym.javamind.javadatetime;

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;

/**
 * DateRange 类实现了 Iterable<LocalDate> 接口，用于提供遍历日期范围的功能。
 * 该类主要提供了创建日期范围迭代器、流和列表的方法。
 */
public class DateRange implements Iterable<LocalDate> {

    private final LocalDate startDate;
    private final LocalDate endDate;

    /**
     * 构造函数，使用开始日期和结束日期初始化 DateRange 实例。
     * 在构造之前，确保日期范围有效（即开始a日期不晚于结束日期）。
     *
     * @param startDate 开始日期，不能为空。
     * @param endDate   结束日期，不能为空。
     * @throws IllegalArgumentException 如果 startDate 为 null, endDate 为 null 或者 startDate 晚于 endDate。
     */
    public DateRange(LocalDate startDate, LocalDate endDate) {
        if (startDate == null || endDate == null) {
            throw new IllegalArgumentException("Start date and end date cannot be null.");
        }
        if (startDate.isAfter(endDate)) {
            throw new IllegalArgumentException("Start date must not be after end date.");
        }
        this.startDate = startDate;
        this.endDate = endDate;
    }

    /**
     * 返回一个迭代器，用于遍历日期范围内的所有日期。
     * 该方法内部调用 stream() 方法来获取迭代器。
     *
     * @return 包含从开始日期到结束日期（包括）的所有日期的迭代器。
     */
    @Override
    public Iterator<LocalDate> iterator() {
        return stream().iterator();
    }

    /**
     * 创建并返回一个包含日期范围内所有日期的流。
     * 流通过从开始日期递增一天生成，直到达到结束日期。
     *
     * @return 包含从开始日期到结束日期（包括）的所有日期的流。
     */
    public Stream<LocalDate> stream() {
        return Stream.iterate(startDate, d -> d.plusDays(1))
                .limit(ChronoUnit.DAYS.between(startDate, endDate) + 1);
    }

    /**
     * 创建并返回一个包含日期范围内所有日期的列表。
     * 列表通过从开始日期递增一天生成，直到达到结束日期。
     *
     * @return 包含从开始日期到结束日期（包括）的所有日期的列表。
     */
    public List<LocalDate> toList() { // 也可以通过 stream() 方法构建
        List<LocalDate> dates = new ArrayList<>();
        for (LocalDate d = startDate; !d.isAfter(endDate); d = d.plusDays(1)) {
            dates.add(d);
        }
        return dates;
    }
}

